/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2Image.h 28 2012-07-28 17:03:06Z trzntaat $
 * $Revision: 28 $
 */

#ifndef T2IMAGE_H_INCLUDED
#define T2IMAGE_H_INCLUDED


namespace turska
{

    //! Image drawing modes.
    enum IMAGE_DRAW_MODE
    {
        IDM_NORMAL = 0,     //!< Normal alpha-blended image drawing.
        IDM_ADD,            //!< Additive image drawing.
        IDM_MULTIPLY,       //!< Multiplicative image drawing.
        IDM_PREMUL_NORMAL,  //!< Normal alpha-blended with premultiplied alpha image.
        IDM_PREMUL_ADD,     //!< Additive with premultiplied alpha image.
        //! Count of image drawing modes.
        IMAGE_DRAW_MODE_COUNT // Do not add new draw modes after this one.
    };

    //! Drawing flags for image features to use when drawing.
    /*! Note that implementations are free to ignore selected flags.
     * For example, a simple software rendered implementation might
     * ignore rotation or filtering flags.
     *
     * The vertical alignment flags are mutually exclusive with each
     * other, and similarly horizontal flags are mutually exclusive
     * with each other. If mutually exclusive alignment flags are
     * combined, center flag is given higher priority.
     */
    enum IMAGE_FLAG
    {
        //! Multiplies source image with color when drawing.
        IF_COLOR                = (1 << 0),
        //! Multiplies source image with alpha when drawing.
        IF_ALPHA                = (1 << 1),

        //! Align horizontally to left edge (default).
        IF_ALIGN_LEFT           = 0,
        //! Align horizontally to pivot (center by default).
        IF_ALIGN_HORIZ_CENTER   = (1 << 2),
        //! Align horizontally to right edge.
        IF_ALIGN_RIGHT          = (1 << 3),
        //! Align vertically to top edge (default).
        IF_ALIGN_TOP            = 0,
        //! Align vertically to pivot (center by default).
        IF_ALIGN_VERT_CENTER    = (1 << 4),
        //! Align vertically to bottom.
        IF_ALIGN_BOTTOM         = (1 << 5),

        // Alignment shortcuts:
        //! Align to left center.
        IF_ALIGN_LEFT_VCENTER   = IF_ALIGN_LEFT | IF_ALIGN_VERT_CENTER,
        //! Align to top-left corner.
        IF_ALIGN_TOP_LEFT       = IF_ALIGN_LEFT | IF_ALIGN_TOP,
        //! Align to top center.
        IF_ALIGN_TOP_HCENTER    = IF_ALIGN_HORIZ_CENTER | IF_ALIGN_TOP,
        //! Align to top-right corner.
        IF_ALIGN_TOP_RIGHT      = IF_ALIGN_RIGHT | IF_ALIGN_TOP,
        //! Align to bottom-left corner.
        IF_ALIGN_BOTTOM_LEFT    = IF_ALIGN_LEFT | IF_ALIGN_BOTTOM,
        //! Align to bottom center.
        IF_ALIGN_BOTTOM_HCENTER = IF_ALIGN_HORIZ_CENTER | IF_ALIGN_BOTTOM,
        //! Align to bottom-right corner.
        IF_ALIGN_BOTTOM_RIGHT   = IF_ALIGN_RIGHT | IF_ALIGN_BOTTOM,
        //! Align to right center.
        IF_ALIGN_RIGHT_VCENTER  = IF_ALIGN_RIGHT | IF_ALIGN_VERT_CENTER,
        //! Center image with given pivot (default is center).
        IF_ALIGN_CENTER         = IF_ALIGN_HORIZ_CENTER | IF_ALIGN_VERT_CENTER,

        //! Flip (mirror) image horizontally.
        IF_FLIP_HORIZ           = (1 << 6),
        //! Flip (mirror) image vertically.
        IF_FLIP_VERT            = (1 << 7),

        /*! Enables transformation. When IF_TRANSFORM is disabled, drawing
         *  uses target width & height and alignment flags. When IF_TRANSFORM
         *  is enabled, drawing uses IF_ROTATE and IF_SCALE flags.
         */
        IF_TRANSFORM            = (1 << 8),
        //! Rotates image when drawing.
        IF_ROTATE               = (1 << 9),
        //! Applies scaling to image. See setScale() methods.
        IF_SCALE                = (1 << 10),

        //! Forces float coordinates of image drawing to be floored to integer boundaries.
        IF_FORCE_INT            = (1 << 11),

        //! Uses bilinear filtering for image sampling if available.
        /*! Recommended for use when images will be scaled.
         * Default is to use nearest neighbor sampling.
         * \note This flag should be set when loading images.
         */
        IF_FILTER_LINEAR        = (1 << 16),

        //! Uses linear filtering between mipmaps.
        /*! Recommended for use when images may be scaled very small.
         * \note This flag should be set when loading images.
         */
        IF_FILTER_LINEAR_MIPMAP = (1 << 17),

        //! Uses/generates mipmaps.
        /*! Recommended for use when images may be scaled very small.
         * \note Using IF_FILTER_LINEAR_MIPMAP without IF_FILTER_LINEAR
         *       is allowed, but may not be supported by all implementations.
         * \note This flag should be set when loading images.
         */
        IF_USE_MIPMAPS          = (1 << 18),

        //! Uses mipmaps and tri-linear filtering.
        /*! \note This flag should be set when loading images.
         */
        IF_FILTER_TRILINEAR     = IF_FILTER_LINEAR | IF_FILTER_LINEAR_MIPMAP | IF_USE_MIPMAPS,

        //! Configures image wrap mode to clamp to edge.
        /*! \note This flag should be set when loading images.
         */
        IF_WRAP_CLAMP_EDGE      = (1 << 19),

        //! Configures image wrap mode to repeat. Default is to clamp.
        /*! \note This flag should be set when loading images.
         */
        IF_WRAP_REPEAT          = (1 << 20),

        //! Hint that image should be loaded using only 16 bits per pixel. (Default is 32 bpp)
        /*! \note This flag should be set when loading images.
         */
        IF_LOAD_16BIT           = (1 << 21),

        //! Load image discarding alpha.
        /*! \note This flag should be set when loading images.
         */
        IF_LOAD_DISCARD_ALPHA   = (1 << 22),

        // TODO: Support for 8/16 bit images loaded only as luminance/alpha/both?

        //! Default flags for image.
        IF_DEFAULT_FLAGS        = IF_COLOR | IF_ALPHA | IF_ALIGN_TOP_LEFT |
                                  IF_FILTER_LINEAR | IF_WRAP_CLAMP_EDGE
    };
    
    
    //! Abstract interface for a container of a static UI image.
    /*! \note Implementation of this class may not support all
     *        features defined by the interface.
     */
    class Image
    {
    public:

        //! Initializes image with given values.
        /*!
         * \param width width of the image.
         * \param height height of the image.
         * \param drawMode initial drawing mode to use, default is IDM_NORMAL.
         * \param flags initial flags to use. \sa IF_DEFAULT_FLAGS
         */
        Image(UI32 width, UI32 height,
              IMAGE_DRAW_MODE drawMode = IDM_NORMAL,
              UI32 flags = IF_DEFAULT_FLAGS) :
            mWidth(width), mHeight(height), mFlags(flags),
            mDrawMode(drawMode), mUsingSourceRectangle(false),
            mPivotX(0), mPivotY(0), mUsingCustomPivot(false) // pivot reference point is center of image
            {}

        virtual ~Image() {}


        inline TREAL getWidth() const { return mUsingSourceRectangle ? mSourceRectangle.width : (TREAL)mWidth; }
        inline TREAL getHeight() const { return mUsingSourceRectangle ? mSourceRectangle.height : (TREAL)mHeight; }

        inline UI32 getOriginalWidth() const { return mWidth; }
        inline UI32 getOriginalHeight() const { return mHeight; }

        inline void setFlags(UI32 flags) { mFlags = flags; }
        inline UI32 getFlags() const { return mFlags; }
        inline void setFlag(UI32 flag) { mFlags |= flag; }
        inline void clearFlag(UI32 flag) { mFlags &= ~flag; }
        inline void setFlagState(UI32 flag, bool enabled)
            { enabled ? setFlag(flag) : clearFlag(flag); }
        inline bool isFlag(UI32 flag) const { return (mFlags & flag) == flag; }

        //! Sets drawing mode. \sa IMAGE_DRAW_MODE
        inline void setDrawMode(IMAGE_DRAW_MODE drawMode) { mDrawMode = drawMode; }

        //! Returns current drawing mode. \sa IMAGE_DRAW_MODE
        inline IMAGE_DRAW_MODE getDrawMode() const { return mDrawMode; }


        //! Sets the color and alpha to use when IF_COLOR or IF_ALPHA flags are enabled.
        virtual void setColor(const Color &color) = 0;


        //! Sets target rectangle size to use when IF_TRANSFORM flag is disabled.
        /*! \note Value scale is the display unit size in use, typically pixels.
         */
        virtual void setTargetSize(TREAL width, TREAL height) = 0;

        //! Disables previously set explicit target rectangle size.
        virtual void resetTargetSize() = 0;

        //! Sets rotation angle to use when IF_ROTATE flag is enabled.
        /*! \param angle rotation angle in radians.
         */
        virtual void setAngle(TREAL angle) = 0;

        //! Sets the scaling factor to use when IF_SCALE flag is enabled.
        virtual void setScale(TREAL scale) = 0;

        //! Sets non-uniform scaling factors to use when IF_SCALE flag is enabled.
        virtual void setScale(TREAL scaleX, TREAL scaleY) = 0;

        //! Sets pivot to use when center alignment flag is enabled. Default is the center of image.
        virtual void setPivot(TREAL centerX, TREAL centerY) { mPivotX = centerX; mPivotY = centerY; mUsingCustomPivot = true; }
        //! Resets pivot to center of image.
        virtual void resetPivot() { mPivotX = mPivotY = 0; mUsingCustomPivot = false; }

        //! Sets source rectangle. Use null to reset source rectangle.
        virtual void setSourceRectangle(const Rectangle *r)
        {
            mUsingSourceRectangle = false;
            if (r)
            {
                mSourceRectangle = *r;
                mUsingSourceRectangle = true;
            }
        }

        //! Returns true if source rectangle is being used, or false if not.
        bool isUsingSourceRectangle() const { return mUsingSourceRectangle; }
        //! Returns current source rectangle. Remember to check isUsingSourceRectangle() as well.
        const Rectangle & getSourceRectangle() { return mSourceRectangle; }


        //! Draws image using current flags, with reference point (x,y).
        virtual void draw(TREAL x, TREAL y) = 0;


        //! Draws image using given drawing mode and flags.
        virtual void draw(IMAGE_DRAW_MODE drawMode, UI32 flags,
                          TREAL x, TREAL y, const Rectangle *sourceRect = 0) = 0;


        //! Draws image using given drawing mode, flags, color and alpha.
        virtual void draw(IMAGE_DRAW_MODE drawMode, UI32 flags,
                          TREAL x, TREAL y, const Color &color, const Rectangle *sourceRect = 0) = 0;

    protected:

        UI32 mWidth;      //!< Image width.
        UI32 mHeight;     //!< Image height.
        UI32 mFlags;      //!< Current flag state. \sa FLAGS
        IMAGE_DRAW_MODE mDrawMode; //!< Current drawing mode. \sa DRAW_MODE
        bool mUsingSourceRectangle;
        Rectangle mSourceRectangle;
        TREAL mPivotX, mPivotY;
        bool mUsingCustomPivot;

    }; // class Image

} // namespace turska


#endif // !T2IMAGE_H_INCLUDED
